#ifndef COMPONENTS_H
#define COMPONENTS_H

#include "Core/UUID.h"
#include "Renderer/texture.h"
#include "Scene/Mesh.h"
#include "Scene/Physics.h"
#include "Scene/Script.h"
#include "Renderer/camera.h"
#include "Renderer/font.h"
#include "Renderer/shader.h"
#include "Renderer/framebuffer.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp>

#include <unordered_map>

namespace CC
{
    #define RANDOM01 ((float)(rand() % 100)/100.0f) //0~1
    #define RANDOM05 ((float)(rand() % 100)/50.0f - 1.0f) //-1~1

    typedef enum {
        ComponentType_ID = 0,
        ComponentType_Tag,
        ComponentType_Transform,
        ComponentType_Light,
        ComponentType_Material2D,
        ComponentType_MeshBasicMaterial,
        ComponentType_LineBasicMaterial,
        ComponentType_MeshModelMaterial,
        ComponentType_MeshCubeMaterial,
        ComponentType_Custom2DMaterial,
        ComponentType_Custom3DMaterial,
        ComponentType_Model,
        ComponentType_Mesh,
        ComponentType_Animation,//bone anim
        ComponentType_RigidBody,
        ComponentType_Camera,
        ComponentType_Script,
        ComponentType_Font,
        ComponentType_Shader,
        ComponentType_MouseArea,
        ComponentType_Emitter,
        ComponentType_Particle2D,
        ComponentType_MAX,
    }ComponentType;

    typedef enum {
        TagType_Default = 0,
        TagType_FPS,
        TagType_Arrow,
        TagType_ArrowAxisX,
        TagType_ArrowAxisY,
        TagType_ArrowAxisZ,
        TagType_DragMove,
        TagType_DragMoveStatic,//photo border
        TagType_DragMoveStaticPhoto1,//photo border
        TagType_DragMoveStaticPhoto2,//photo border
        TagType_DragMoveStaticPhoto3,//photo border
        TagType_DragMoveStaticVideo,
        TagType_DragMoveStaticCar,
        TagType_DragMoveDynamicTrash,
        TagType_DragMoveDynamicExit,
        TagType_DragMoveIcon,
        TagType_Ground,
        TagType_Enemy,
    }TagType;

    class Component
    {
        public:
        ComponentType componentType;

        Component() = default;
        Component(const Component &) = default;
        virtual ~Component() {}
    };

    class IDComponent: public Component
    {
        public:
        UUID ID;

        IDComponent(){
            componentType = ComponentType_ID;
        }
        IDComponent(const IDComponent &) = default;
        IDComponent(UUID id) :ID(id){
            componentType = ComponentType_ID;
        }
        virtual ~IDComponent() {}
    };

    class TagComponent: public Component
    {
        public:
        std::string Tag;
        bool Visible = true;
        bool VisibleEditor = true;
        std::string RenderPassTag = "opaque";        

        TagType Type = TagType_Default;
        TagType SubType = TagType_Default;

        TagComponent() {
            componentType = ComponentType_Tag;
        }
        TagComponent(const TagComponent &) = default;
        TagComponent(const std::string &tag)
            : Tag(tag) {
            componentType = ComponentType_Tag;
        }
        virtual ~TagComponent() {}
    };

    class TransformComponent: public Component
    {
        public:
        glm::vec3 Translation = {0.0f, 0.0f, 0.0f};
        glm::vec3 Rotation = {0.0f, 0.0f, 0.0f};
        glm::vec3 Scale = {1.0f, 1.0f, 1.0f};

        glm::mat4 CustomTransform = glm::mat4(1.0);

        TransformComponent() {
            componentType = ComponentType_Transform;
        }
        TransformComponent(const TransformComponent &) = default;
        TransformComponent(const glm::vec3 &translation)
            : Translation(translation) {
            componentType = ComponentType_Transform;
        }

        TransformComponent(const glm::vec3 &translation, const glm::vec3 &rotation, const glm::vec3 &scale)
            : Translation(translation), Rotation(rotation), Scale(scale) {
            componentType = ComponentType_Transform;
        }

        glm::mat4 GetTransform() const
        {
            if (CustomTransform != glm::mat4(1.0)) return CustomTransform;

            glm::qua<float> q = glm::qua<float>(Rotation);
            glm::mat4 rotation = glm::mat4_cast(q);

            return glm::translate(glm::mat4(1.0f), Translation) * rotation * glm::scale(glm::mat4(1.0f), Scale);
        }
        glm::mat4 GetTransform(glm::vec3 parentScale) const
        {
            if (CustomTransform != glm::mat4(1.0)) return CustomTransform;

            glm::qua<float> q = glm::qua<float>(Rotation);
            glm::mat4 rotation = glm::mat4_cast(q);

            return glm::translate(glm::mat4(1.0f), Translation * parentScale) * rotation * glm::scale(glm::mat4(1.0f), Scale);
        }
        glm::mat4 GetTransformNoScale() const
        {
            if (CustomTransform != glm::mat4(1.0)) return CustomTransform;

            glm::qua<float> q = glm::qua<float>(Rotation);
            glm::mat4 rotation = glm::mat4_cast(q);

            return glm::translate(glm::mat4(1.0f), Translation) * rotation;
        }
        glm::mat4 GetTransformNoScale(glm::vec3 parentScale) const
        {
            if (CustomTransform != glm::mat4(1.0)) return CustomTransform;

            glm::qua<float> q = glm::qua<float>(Rotation);
            glm::mat4 rotation = glm::mat4_cast(q);

            return glm::translate(glm::mat4(1.0f), Translation * parentScale) * rotation;
        }
        void CalcCustomTransformByBoneMat(glm::mat4 mat) {

            glm::qua<float> q = glm::qua<float>(Rotation);
            glm::mat4 rotation = glm::mat4_cast(q);

            glm::mat4 a = glm::translate(glm::mat4(1.0f), Translation) * rotation * glm::scale(glm::mat4(1.0f), Scale);

            CustomTransform = a * mat;
        }
        virtual ~TransformComponent() {}
    };

    class LightComponent: public Component
    {
        public:
        glm::vec4 Color{ 1.0f, 1.0f, 1.0f, 1.0f };
        glm::vec4 Position{ 0.0f, 0.0f, 0.0f, 0.0f };//w=0,direct light;w=1,point light
        float Intensity;

        LightComponent() {
            componentType = ComponentType_Light;
        }
        LightComponent(const LightComponent &) = default;
        LightComponent(const glm::vec4 &color)
            : Color(color), Intensity(1.0) {
            componentType = ComponentType_Light;
        }
        virtual ~LightComponent() {}
    };

    // Material =========================
    class Material2DComponent: public Component
    {
        public:
        glm::vec4 Color{1.0f, 1.0f, 1.0f, 1.0f};
        Texture2D *Texture = nullptr;
        float TilingFactor = 1.0f;

        Material2DComponent() {
            componentType = ComponentType_Material2D;
        }
        Material2DComponent(const Material2DComponent &) = default;
        Material2DComponent(const glm::vec4 &color)
            : Color(color) {
            componentType = ComponentType_Material2D;
        }
        virtual ~Material2DComponent() {}
    };

    class MeshBasicMaterialComponent: public Component
    {
        public:
        glm::vec4 Color{1.0f, 1.0f, 1.0f, 1.0f};
        Texture2D *Texture = nullptr;
        float TilingFactor = 1.0f;

        MeshBasicMaterialComponent() {
            componentType = ComponentType_MeshBasicMaterial;
        }
        MeshBasicMaterialComponent(const MeshBasicMaterialComponent &) = default;
        MeshBasicMaterialComponent(const glm::vec4 &color)
            : Color(color) {
            componentType = ComponentType_MeshBasicMaterial;
        }
        virtual ~MeshBasicMaterialComponent() {}
    };

    class LineBasicMaterialComponent : public Component
    {
    public:
        glm::vec4 Color{ 1.0f, 1.0f, 1.0f, 1.0f };
        glm::vec3 StartPoint;
        glm::vec3 EndPoint;

        LineBasicMaterialComponent() {
            componentType = ComponentType_LineBasicMaterial;
        }
        LineBasicMaterialComponent(const LineBasicMaterialComponent &) = default;
        LineBasicMaterialComponent(const glm::vec4 &color)
            : Color(color), StartPoint(glm::vec3(0.0)), EndPoint(glm::vec3(0.0)) {
            componentType = ComponentType_LineBasicMaterial;
        }
        virtual ~LineBasicMaterialComponent() {}
    };

    class MeshModelMaterialComponent: public Component
    {
        public:
        bool HasColorMaterial = true;
        bool EanbleLight = true;
        bool EanbleGenerateShadow = false;
        bool EanbleDisplayShadow = false;
        MaterialMesh MaterialMeshType;
        std::vector<Texture2D *> Textures;
        float TilingFactor = 1.0f;

        MeshModelMaterialComponent() {
            componentType = ComponentType_MeshModelMaterial;
        }
        MeshModelMaterialComponent(const MeshModelMaterialComponent &) = default;
        MeshModelMaterialComponent(bool has, MaterialMesh m, std::vector<Texture2D *> t, float tf = 1.0f)
            : HasColorMaterial(has), MaterialMeshType(m), Textures(t), TilingFactor(tf) {
            componentType = ComponentType_MeshModelMaterial;
        }

        MeshModelMaterialComponent(bool has, MaterialMesh m, float tf = 1.0f)
            : HasColorMaterial(has), MaterialMeshType(m), TilingFactor(tf) {
            componentType = ComponentType_MeshModelMaterial;
        }
        virtual ~MeshModelMaterialComponent() {}
    };

    class MeshCubeMaterialComponent : public Component
    {
    public:
        glm::vec4 Color{ 1.0f, 1.0f, 1.0f, 1.0f };
        TextureCube *Texture = nullptr;
        float TilingFactor = 1.0f;

        MeshCubeMaterialComponent() {
            componentType = ComponentType_MeshCubeMaterial;
        }
        MeshCubeMaterialComponent(const MeshCubeMaterialComponent &) = default;
        MeshCubeMaterialComponent(TextureCube* t, const glm::vec4 &color)
            : Texture(t), Color(color) {
            componentType = ComponentType_MeshCubeMaterial;
        }
        virtual ~MeshCubeMaterialComponent() {}
    };

    class Custom2DMaterialComponent : public Component
    {
    public:
        enum DataType
        {
            DataType_Int = 0,
            DataType_Int2,
            DataType_Int3,
            DataType_Int4,
            DataType_Float,
            DataType_Float2,
            DataType_Float3,
            DataType_Float4,
            DataType_Texture,
        };
        struct DataInfo
        {
            DataType dataType;
            int a4[4];
            float b4[4];
            Texture2D* texture2D;

            DataInfo() {}

            DataInfo(DataType t, int v1, int v2 = 0, int v3 = 0, int v4 = 0) : dataType(t){
                a4[0] = v1;
                a4[1] = v2;            
                a4[2] = v3;            
                a4[3] = v4;            
            }

            DataInfo(DataType t, float v1, float v2 = 0.0, float v3 = 0.0, float v4 = 0.0) : dataType(t) {
                b4[0] = v1;
                b4[1] = v2;
                b4[2] = v3;
                b4[3] = v4;
            }

            DataInfo(DataType t, Texture2D* tex) : dataType(t), texture2D(tex) {
            }
        };

        std::unordered_map<std::string, DataInfo> datas;

        Custom2DMaterialComponent() {
            componentType = ComponentType_Custom2DMaterial;
        }
        Custom2DMaterialComponent(const Custom2DMaterialComponent &) = default;
        virtual ~Custom2DMaterialComponent() {}
    };

    class Custom3DMaterialComponent : public Component
    {
    public:
        enum DataType
        {
            DataType_Int = 0,
            DataType_Int2,
            DataType_Int3,
            DataType_Int4,
            DataType_Float,
            DataType_Float2,
            DataType_Float3,
            DataType_Float4,
            DataType_Texture,
        };
        struct DataInfo
        {
            DataType dataType;
            int a4[4];
            float b4[4];
            Texture2D* texture2D;

            DataInfo() {}

            DataInfo(DataType t, int v1, int v2 = 0, int v3 = 0, int v4 = 0) : dataType(t) {
                a4[0] = v1;
                a4[1] = v2;
                a4[2] = v3;
                a4[3] = v4;
            }

            DataInfo(DataType t, float v1, float v2 = 0.0, float v3 = 0.0, float v4 = 0.0) : dataType(t) {
                b4[0] = v1;
                b4[1] = v2;
                b4[2] = v3;
                b4[3] = v4;
            }

            DataInfo(DataType t, Texture2D* tex) : dataType(t), texture2D(tex) {
            }
        };

        std::unordered_map<std::string, DataInfo> datas;

        Custom3DMaterialComponent() {
            componentType = ComponentType_Custom3DMaterial;
        }
        Custom3DMaterialComponent(const Custom3DMaterialComponent &) = default;
        virtual ~Custom3DMaterialComponent() {}
    };
    // Material =========================

    class ModelComponent: public Component
    {
        public:
        std::string Path;        

        ModelComponent() {
            componentType = ComponentType_Model;
        }
        ModelComponent(const ModelComponent &) = default;
        ModelComponent(const std::string p)
            : Path(p) {
            componentType = ComponentType_Model;
        }
        virtual ~ModelComponent() {}
    };

    class MeshComponent: public Component
    {
        public:
        Mesh MeshData;
        Mesh* MeshDataInstance = nullptr;

        MeshComponent() {
            componentType = ComponentType_Mesh;
        }
        MeshComponent(const MeshComponent &) = default;
        MeshComponent(const Mesh m)
            : MeshData(m) {
            componentType = ComponentType_Mesh;
        }
        virtual ~MeshComponent() {}
    };

    class AnimationComponent: public Component
    {
        public:
        // Mesh MeshData;
        Animator *AnimatorObject=NULL;
        AnimationInfo AnimationInfoData;
        std::string CurrentAnimatioName = "";
        std::string LastAnimatioName = "";
        bool AnimationLoop = true;
        bool AnimationFinish = false;
        double AnimationMixTime = 0.0;
        double AnimationSpeed = 1.0;
        int AnimationCurrentFrame = 0;
        bool AnimationPlaying = false;

        AnimationComponent() {
            componentType = ComponentType_Animation;
        }
        AnimationComponent(const AnimationComponent &a) = default;

        AnimationComponent(AnimationInfo& a) :AnimationInfoData(a)
        {
            CC_CORE_INFO("~~~*************~AnimationComponent(AnimationInfo& a)\n");
            if (AnimatorObject) {
                delete AnimatorObject;
                AnimatorObject = NULL;
            }
            AnimatorObject = new Animator;
            componentType = ComponentType_Animation;
        }

        virtual ~AnimationComponent() {
            CC_CORE_INFO("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~AnimationComponent\n");
            //delete AnimatorObject;
            //AnimatorObject = NULL;
        }

        void AddAnimation(std::string name, std::string animationPath)
        {
            if (AnimationInfoData.BoneCounter == 0) {
                CC_CORE_INFO("BoneCounter=0\n");
                return;
            }

            if (AnimationInfoData.AnimationInfoMap.find(name) != AnimationInfoData.AnimationInfoMap.end()) {
                CC_CORE_INFO("Anim has add\n");
                return;
            }

             Animation *animation = new Animation(animationPath, AnimationInfoData);
             AnimationInfoData.AnimationInfoMap[name] = animation;// Animation(animationPath, AnimationInfoData);
        }

        void DelAnimation(std::string name)
        {
            auto it = AnimationInfoData.AnimationInfoMap.find(name);
            if(it == AnimationInfoData.AnimationInfoMap.end())
                return;

            if (name == CurrentAnimatioName) {
                CurrentAnimatioName = "";
                StopAnimation();
            }

            delete it->second;
            AnimationInfoData.AnimationInfoMap.erase(it);
        }

        bool PlayAnimation(std::string name, bool repeate=true){
            if (AnimationInfoData.AnimationInfoMap.find(name) == AnimationInfoData.AnimationInfoMap.end()) {
                CurrentAnimatioName = "";
                return false;
            }
            //if(CurrentAnimatioName == name) return false;
            if (CurrentAnimatioName != name) {
                AnimationPlaying = false;
            }
            if (AnimationPlaying) return false;
            AnimationPlaying = true;

            AnimationLoop = repeate;

            if(!repeate){
                LastAnimatioName = CurrentAnimatioName;
                AnimationFinish = false;
            }

            CurrentAnimatioName = name;

            if(AnimatorObject)
                AnimatorObject->PlayAnimation(AnimationInfoData.AnimationInfoMap[name], AnimationMixTime);
            return true;
        }
        void StopAnimation(){
            if (AnimatorObject)
                AnimatorObject->StopAnimation();
            AnimationPlaying = false;
        }
        void Clear() {
            CurrentAnimatioName = LastAnimatioName = "";

            AnimationLoop = true;
            AnimationFinish = false;
            AnimationMixTime = 0.0;
            AnimationSpeed = 1.0;
            AnimationPlaying = false;
        }
    };

    class RigidBodyComponent: public Component
    {
        public:
        RigidBody RigidBodyData;

        RigidBodyComponent() {
            componentType = ComponentType_RigidBody;
        }
        RigidBodyComponent(const RigidBodyComponent &) = default;
        RigidBodyComponent(const RigidBody r)
            : RigidBodyData(r) {
            componentType = ComponentType_RigidBody;
        }
        virtual ~RigidBodyComponent() {}
    };

    class CameraComponent: public Component
    {
        public:
        Camera *camera;
        bool Primary = true; // TODO: think about moving to Scene
        bool Type2d = true;  // camera 2d
        bool FixedAspectRatio = false;

        CameraComponent() {
            componentType = ComponentType_Camera;
        }
        CameraComponent(const CameraComponent &) = default;
        CameraComponent(Camera* c, bool p, bool t, bool f) : camera(c), Primary(p), Type2d(t), FixedAspectRatio(f) {
            componentType = ComponentType_Camera;
        }
        virtual ~CameraComponent() {}
    };

    class ScriptComponent: public Component
    {
        public:
        std::string ClassName;
        std::string Path;
        Script *ScriptObject = nullptr;

        ScriptComponent() {
            componentType = ComponentType_Script;
        }
        ScriptComponent(const ScriptComponent &) = default;
        ScriptComponent(const std::string c="", const std::string p=""): ClassName(c), Path(p) {
            componentType = ComponentType_Script;
        }
        virtual ~ScriptComponent() {}
    };

    class FontComponent: public Component
    {
        public:
        Font* font;
        float scale = 1.0f; // output 100 * 0.16 = 16px
        std::string text = ""; //del
        std::wstring wtext;
        unsigned int fontSize = 16;

        FontComponent() {
            componentType = ComponentType_Font;
        }
        FontComponent(const FontComponent &) = default;
        FontComponent(Font* f, const float &s = 1.0, const unsigned int &fs = 40)
            : font(f), scale(s), fontSize(fs) {
            componentType = ComponentType_Font;
        }
        virtual ~FontComponent() {}
    };

    class ShaderComponent : public Component
    {
    public:
        Shader* shader;

        ShaderComponent() {
            componentType = ComponentType_Shader;
        }
        ShaderComponent(const ShaderComponent &) = default;
        ShaderComponent(Shader* s)
            : shader(s){
            componentType = ComponentType_Shader;
        }
        virtual ~ShaderComponent() {}
    };

    class MouseAreaComponent : public Component
    {
    public:
        MouseAreaComponent() {
            componentType = ComponentType_MouseArea;
        }
        MouseAreaComponent(const MouseAreaComponent &) = default;

        virtual ~MouseAreaComponent() {}

        typedef std::function<void(Event*, Entity*)> MouseAreaEventCallbackFn;

        template <typename T>
        void AddHandler(const MouseAreaEventCallbackFn &func) {
            m_funcs[T::GetStaticType()] = func;
        }

        void OnEvent(Event &event, Entity* e)
        {
            std::unordered_map<EventType, MouseAreaEventCallbackFn>::iterator it = m_funcs.begin();
            for (it; it != m_funcs.end(); ++it) {
                if (event.GetEventType() == it->first)
                {
                    it->second(&event, e);
                    break;
                }
            }
        }

        std::unordered_map<EventType, MouseAreaEventCallbackFn> m_funcs;
    };

    class EmitterComponent : public Component
    {
    public:
        EmitterComponent(TransformComponent* t): transformComponent(t) {
            componentType = ComponentType_Emitter;
        }
        EmitterComponent(const EmitterComponent &) = default;

        virtual ~EmitterComponent() {}

        struct Particle {
            TransformComponent Tran;           
            float Life;
            glm::vec4 Color;
            float MaxLife;
            bool used;
            float Angle;
            glm::vec3 StartSpeed = glm::vec3(0.0, 0.0, 0.0);
            glm::vec3 EndSpeed = glm::vec3(0.0, 0.0, 0.0);
            Particle() { }
        };

        enum Emitter_Type
        {
            Emitter_Type_Point = 0,
            Emitter_Type_Line,
            Emitter_Type_BoxIn,
            Emitter_Type_BoxBorder,
            Emitter_Type_Mesh,
            Emitter_Type_RECTANGE,
        };

        void Start(){}
        void Stop(){}
        //deltaTime unit /s
        void Update(float deltaTime){

            if(burst){
                static bool needNewParticle = true;

                static float timespan = 0.0;
                timespan += deltaTime;

                if(timespan >= 1.0) {
                    timespan -= 1.0;
                    needNewParticle = true;
                }

                for (unsigned int i = 0; i < emitRate && i < poolsize && needNewParticle; ++i)
                {
                    int unusedParticle = firstUnusedParticle();
                    if(unusedParticle != -1)
                        respawnParticle(particles[unusedParticle]);
                }
                needNewParticle = false;
            }
            else{
                float emitRateTimeSpan = 1.0f / (float)emitRate;

                static float timespan = 0.0;
                timespan += deltaTime;

                if (timespan >= emitRateTimeSpan) {
                    bool needNewParticle = true;
                    if (!repeated) {
                        needNewParticle = lastUsedParticle < poolsize - 1;
                    }

                    int num = timespan / emitRateTimeSpan;
                    timespan -= emitRateTimeSpan * num;
                    timespan = timespan > 0.0f ? timespan : 0.0f;

                    for (unsigned int i = 0; i < num && i < poolsize && needNewParticle; ++i)
                    {
                        int unusedParticle = firstUnusedParticle();
                        if(unusedParticle != -1)
                            respawnParticle(particles[unusedParticle]);
                    }
                }
            }
            

            for (unsigned int i = 0; i < poolsize; ++i){
                Particle& particle = particles[i];
                
                if (particle.Life > 0.0f){
                    particle.used = true;
                    float escapeTime = particle.MaxLife - particle.Life; //escape time
                    float radio = escapeTime / particle.MaxLife;
                    radio = radio > 1.0 ? 1.0 : radio;

                    glm::vec3 currentSpeed = (particle.EndSpeed - particle.StartSpeed) * radio + particle.StartSpeed;
                    glm::vec3 currentSize = (endSize - startSize) * radio + startSize;
                    glm::vec4 currentColor = (endColor - startColor) * radio + startColor;


                    //glm::mat4 model_mt_local = glm::mat4(1.0f);
                    //glm::mat4 mat = CC::Tool::RotateByLocalAngle(model_mt_local, glm::vec3(0.0, 0.0, particle.Angle));
                    //glm::vec3 v = glm::vec3(mat * (glm::normalize(glm::vec4(currentSpeed[0], currentSpeed[1],currentSpeed[2], 1.0))));

                    unsigned int len = currentSpeed[0] * currentSpeed[0] + currentSpeed[1] * currentSpeed[1] + currentSpeed[2] * currentSpeed[2];
                    len = sqrt(len);

                    glm::vec3 v = glm::vec3(0.0);
                    v[0] = cos(glm::radians(particle.Angle)) * len * deltaTime;
                    v[1] = sin(glm::radians(particle.Angle)) * len * deltaTime;

                    particle.Tran.Translation += v;
                    //particle.Tran.Rotation = ;
                    particle.Tran.Scale = currentSize;
                    particle.Color = currentColor;
                }
                else{
                    particle.used = false;
                    particle.Color[3] = 0.0;
                }
                particle.Life -= deltaTime; // reduce life
            }
            
        }

        Particle& GetParticle(int index){ return particles[index]; }

        int emitRate = 10;   //Default value is 10 particles per second
        bool repeated = true;
        bool burst = false; //爆发
        float lifeSpan = 1.0;   //Default value is 1 (one second)
        float lifeSpanVariation = 0.0;

        float       angle = 0.0;//扇形
        float       angleVariation = 0.0;

        glm::vec3 startSize = glm::vec3(1.0);
        glm::vec3 endSize = glm::vec3(0.0);

        glm::vec4 startColor = glm::vec4(1.0);
        glm::vec4 endColor = glm::vec4(1.0);

        glm::vec3 startSpeed = glm::vec3(0.0, 1.0, 0.0);
        glm::vec3 startSpeedVariation = glm::vec3(0.0, 0.0, 0.0);
        glm::vec3 endSpeed = glm::vec3(0.0, 1.0, 0.0);

        TransformComponent* transformComponent = nullptr;
        Emitter_Type type = Emitter_Type_Point;
        const int poolsize = 100;

    private:
        Particle particles[100];
        unsigned int lastUsedParticle = 0;        

        int firstUnusedParticle()
        {
            if (repeated) {
                // first search from last used particle, this will usually return almost instantly
                for (unsigned int i = lastUsedParticle; i < poolsize; ++i) {
                    if (particles[i].Life <= 0.0f) {
                        lastUsedParticle = i;
                        return i;
                    }
                }
                // otherwise, do a linear search
                for (unsigned int i = 0; i < lastUsedParticle; ++i) {
                    if (particles[i].Life <= 0.0f) {
                        lastUsedParticle = i;
                        return i;
                    }
                }
                // all particles are taken, override the first one (note that if it repeatedly hits this case, more particles should be reserved)
                lastUsedParticle = 0;

                return 0;
            }
            else {
                for (unsigned int i = lastUsedParticle; i < poolsize; ++i) {
                    if (particles[i].Life <= 0.0f && !particles[i].used) {
                        lastUsedParticle = i;
                        return i;
                    }
                }
                return -1;
            }       
        }

        void respawnParticle(Particle& particle)
        {
            CC_ASSERT(transformComponent, "EmitterComponent transformComponent is null");
            glm::mat4 modoles = transformComponent->GetTransform();

            if (Emitter_Type_Point == type) {
                particle.Tran.Translation = transformComponent->Translation;
                particle.Tran.Rotation = transformComponent->Rotation;
                //particle.Tran.Scale = transformComponent->Scale;
                respawnParticleCommon(particle);
            }
            else if (Emitter_Type_Line == type) {
                
                // //float positionX = CC::getNewPosition(particle.PartNormalK, frequency, amplitude, RANDOM01, true);
                
                // //kzLogDebug(("positionX = {}, rectPosition[0].getX() = {}, rectPosition[0].getY() = {}, rectPosition[0].getZ() = {}", positionX, rectPosition[0].getX(), rectPosition[0].getY(), rectPosition[0].getZ()));
                // //kzLogDebug(("positionX = {}, rectPosition[1].getX() = {}, rectPosition[1].getY() = {}, rectPosition[1].getZ() = {}", positionX, rectPosition[1].getX(), rectPosition[0].getY(), rectPosition[0].getZ()));
            
                // float positionX = CC::getNewPosition(particle.PartNormalK, frequency, amplitude, RANDOM01, false);
                // // particle.PartNormalK = CC::mysin(RANDOM01, frequency, amplitude);


                // //calcEmitterShape(particle, &rectLine[0], positionX, positionX, positionX);
                // calcEmitterShape(particle, &rectLine[0], positionX, positionX, positionX);
                // respawnParticleCommon(particle);

            }
            else if (Emitter_Type_BoxBorder == type) {

                //     float k = RANDOM01;
                // if (k <= 0.33f)
                // {
                //     calcEmitterShape(particle, &rectBox[0], RANDOM01, RANDOM01, RANDOM01 > 0.5f ? 1.0f : 0.0f);

                // }
                // else if (k <= 0.66f)
                // {

                //     calcEmitterShape(particle, &rectBox[0], RANDOM01, RANDOM01 > 0.5f ? 1.0f : 0.0f, RANDOM01);

                // }
                // else
                // {
                //     calcEmitterShape(particle, &rectBox[0], RANDOM01 > 0.5f ? 1.0f : 0.0f, RANDOM01, RANDOM01);

                // }
                // //glm::vec3 a = glm::vec3(modoles * glm::vec4(particle.Position[0], particle.Position[1], particle.Position[2], 1.0));
                // //particle.Position = Vector3(a[0], a[1], a[2]);
                // particle.PartNormalK = 1.0f;
                // respawnParticleCommon(particle);
            }
            else if (Emitter_Type_BoxIn == type)
            {
                    // if (frequency == 0) {

                    //     calcEmitterShape(particle, &rectBox[0], RANDOM01, RANDOM01, RANDOM01);
                    //     //glm::vec3 a = glm::vec3(modoles * glm::vec4(particle.Position[0], particle.Position[1], particle.Position[2], 1.0));
                    //     //particle.Position = Vector3(a[0], a[1], a[2]);
                    //     particle.PartNormalK = 1.0f;
                    // }
                    // else
                    // {
                    //     Vector3 rectPositionTemp[2];
                    //     rectPositionTemp[0] = rectBox[0];
                    //     rectPositionTemp[1] = Vector3(rectBox[1][0], rectBox[0][1], rectBox[1][2]);

                    //     float xWidth = abs(rectPositionTemp[0][0] - rectPositionTemp[1][0]) / 2.0f; //x 轴边长的一半

                    //     float r = RANDOM01;//[0-1]  
                    //     float degree = RANDOM01 * 2.0f * PI3; //角度 [0,2PI]
                    //     Vector3 bottomCenter = (rectPositionTemp[0] + rectPositionTemp[1]) / 2.0f; // 到屏幕中心点的向量
                    //     Vector3 Position = Vector3(bottomCenter[0] + r * (xWidth)*cos(degree),
                    //         bottomCenter[1],
                    //         bottomCenter[2] + r * (xWidth)*sin(degree)); // x 与 z 动   y保持原样不变 
                    //     float ratio = r * 0.5f; //[0,0.5]
                    //     ratio = 0.5f - ratio;//max = 0.5  [0.5,0]

                    //     float positionX = CC::getNewPosition(particle.PartNormalK, frequency, amplitude, ratio, false);
                    //     calcEmitterShape(particle, &rectPositionTemp[0], 0, positionX, 0);//y
                    //     particle.Position[0] = Position[0]; //x
                    //     particle.Position[2] = Position[2]; //y
                    //     //glm::vec3 a = glm::vec3(modoles * glm::vec4(particle.Position[0], particle.Position[1], particle.Position[2], 1.0));
                    //     //particle.Position = Vector3(a[0], a[1], a[2]);
                    // }          
                    // respawnParticleCommon(particle);
            }

        }

        void respawnParticleCommon(Particle &particle)
        {
            particle.Tran.Scale = startSize;
            particle.MaxLife = particle.Life = lifeSpan + RANDOM05 * lifeSpanVariation;
            particle.Color = startColor;
            particle.used = true;
            particle.Angle = angle + RANDOM05 * angleVariation;
            particle.StartSpeed = startSpeed + RANDOM05 * startSpeedVariation;
            particle.EndSpeed = particle.StartSpeed;//linear
        }
    };

    class Particle2DComponent : public Component
    {
    public:
        Particle2DComponent() {
            componentType = ComponentType_Particle2D;
        }
        Particle2DComponent(const Particle2DComponent &) = default;

        virtual ~Particle2DComponent() {}

        void SetEmitter(EmitterComponent* e){
            emitter = e;
        }

        EmitterComponent* GetEmitter(){
            return emitter;
        }

        void Start(){
            state = ParticleSystemState_Running;
            time_t t;
            srand((unsigned)time(&t));

            if(emitter){
                emitter->Start();
            }            
        }
        void Stop(){
            state = ParticleSystemState_Stop;
            if(emitter){
                emitter->Stop();
            }
        }
        void Update(float deltaTime){
            if(state != ParticleSystemState_Running) return;
            if(emitter){
                emitter->Update(deltaTime);
            }
        }

        typedef enum
        {
            ParticleSystemState_Stop = 0,
            ParticleSystemState_Running,
            ParticleSystemState_Pause,
        }ParticleSystemState;

        ParticleSystemState state = ParticleSystemState_Stop;
        EmitterComponent* emitter = nullptr;

    };
}

#endif